/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { ConnectionSpec } from './ConnectionSpec';
import { Dns } from './Dns';
import { HttpUrl } from './HttpUrl';
import { Protocol } from './Protocol';
import { SocketFactory } from './Socket/SocketFactory';
import { SSLSocketFactory } from './Socket/SSLSocketFactory';
import { HostnameVerifier } from './HostnameVerifier';
import { CertificatePinner } from './CertificatePinner';
import { ProxySelector } from './ProxySelector';

export class Address {
    uriHost: string
    uriPort: number
    private _dns: Dns
    private _socketFactory: SocketFactory  // 待完善
    private _sslSocketFactory: SSLSocketFactory | null  // 待完善
    private _hostnameVerifier: HostnameVerifier | null  // 待完善
    private _certificatePinner: CertificatePinner | null  // 待完善
    private _proxyAuthenticator: any  // 待完善
    private _proxy: any  // 待完善
    private _protocols: Protocol[]  // 待完善
    private _connectionSpecs: Array<ConnectionSpec>  // 待完善
    private _proxySelector: ProxySelector  // 待完善
    private _url: HttpUrl | null = null
    constructor(uriHost: string, uriPort: number, dns: Dns, socketFactory, sslSocketFactory: SSLSocketFactory | null, hostnameVerifier: HostnameVerifier | null, certificatePinner: CertificatePinner | null, proxyAuthenticator, proxy, protocols: Protocol[], connectionSpecs: Array<ConnectionSpec>, proxySelector: ProxySelector){
        this.uriHost = uriHost
        this.uriPort = uriPort
        this._dns = dns
        this._socketFactory = socketFactory
        this._sslSocketFactory = sslSocketFactory
        this._hostnameVerifier = hostnameVerifier
        this._certificatePinner = certificatePinner
        this._proxyAuthenticator = proxyAuthenticator
        this._proxy = proxy
        // 创建协议数组的副本以保证不可变性
        this._protocols = [...protocols]
        // 创建连接规范数组的副本以保证不可变性
        this._connectionSpecs = [...connectionSpecs]
        this._proxySelector = proxySelector
    }
    get dns() {
        return this._dns
    }
    get socketFactory():SocketFactory {
        return this._socketFactory
    }
    get sslSocketFactory():SSLSocketFactory {
        return this._sslSocketFactory
    }
    get hostnameVerifier() {
        return this._hostnameVerifier
    }
    get certificatePinner(): CertificatePinner {
        return this._certificatePinner
    }
    get proxyAuthenticator() {
        return this._proxyAuthenticator
    }
    get proxy() {
        return this._proxy
    }
    get protocols(): Array<Protocol> {
        return this._protocols;
    }
    get connectionSpecs(): Array<ConnectionSpec> {
        return this._connectionSpecs
    }
    get proxySelector(): ProxySelector {
        return this._proxySelector
    }
    get url(): HttpUrl {
        // 缓存 URL，避免重复创建
        if (this._url === null) {
            this._url = new HttpUrl.Builder()
                .scheme(this._sslSocketFactory !== null ? "https" : "http")
                .host(this.uriHost)
                .port(this.uriPort)
                .build()
        }
        return this._url
    }

    equals(other: unknown): boolean {
        if (other === null || other === undefined) return false;
        if (!(other instanceof Address)) return false;
        // 比较 URL 的字符串表示
        return this.url.toString() === other.url.toString() &&
            this.equalsNonHost(other);
    }

    hashCode(): number {
        let result = 17
        result = 31 * result + this.hashString(this.url.toString())
        result = 31 * result + (this._dns ? this.hashString(this._dns.toString()) : 0)
        result = 31 * result + (this._proxyAuthenticator ? this.hashString(String(this._proxyAuthenticator)) : 0)
        result = 31 * result + this.hashArray(this._protocols)
        result = 31 * result + this.hashArray(this._connectionSpecs)
        result = 31 * result + (this._proxySelector ? this.hashString(String(this._proxySelector)) : 0)
        result = 31 * result + (this._proxy ? this.hashString(String(this._proxy)) : 0)
        result = 31 * result + (this._sslSocketFactory ? this.hashString(String(this._sslSocketFactory)) : 0)
        result = 31 * result + (this._hostnameVerifier ? this.hashString(String(this._hostnameVerifier)) : 0)
        result = 31 * result + (this._certificatePinner ? this.hashString(String(this._certificatePinner)) : 0)
        return result
    }

    private hashString(str: string): number {
        let hash = 0
        for (let i = 0; i < str.length; i++) {
            const char = str.charCodeAt(i)
            hash = ((hash << 5) - hash) + char
            hash = hash & hash // Convert to 32bit integer
        }
        return hash
    }

    private hashArray(arr: unknown[]): number {
        let hash = 1
        for (const item of arr) {
            hash = 31 * hash + (item ? this.hashString(String(item)) : 0)
        }
        return hash
    }

    // 主要用于连接池复用逻辑; 不需要对比地址是否相等;只对比各个属性是否相等
    equalsNonHost(that: Address): boolean {
        return this._dns === that.dns &&
            this._proxyAuthenticator === that.proxyAuthenticator &&
            this.arraysEqual(this._protocols, that.protocols) &&
            this.arraysEqual(this._connectionSpecs, that.connectionSpecs) &&
            this._proxySelector === that.proxySelector &&
            this.proxyEquals(this._proxy, that.proxy) &&
            this._sslSocketFactory === that.sslSocketFactory &&
            this._hostnameVerifier === that.hostnameVerifier &&
            this._certificatePinner === that.certificatePinner &&
            this.uriPort === that.uriPort
    }

    private arraysEqual<T>(a: T[], b: T[]): boolean {
        if (a.length !== b.length) return false
        for (let i = 0; i < a.length; i++) {
            if (a[i] !== b[i]) return false
        }
        return true
    }

    private proxyEquals(a: any, b: any): boolean {
        if (a === null && b === null) return true
        if (a === null || b === null) return false
        // 如果 proxy 对象有 equals 方法，使用它
        if (typeof a.equals === 'function') {
            return a.equals(b)
        }
        return a === b
    }

    toString(): string {
        return "Address{" +
            `${this.url.host}:${this.url.port}, ` +
            (this._proxy !== null ? "proxy=" + this._proxy : "proxySelector=" + this._proxySelector) +
            "}"
    }
}